package cn.virens.common.util.core;

import cn.virens.common.util.core.stream.StreamUtil;
import cn.virens.common.util.exception.APIException;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import org.dromara.hutool.core.io.file.FileUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.util.CharsetUtil;

import java.io.File;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.stream.IntStream;

public class JSONUtil {

    public static <T> T toObj(JSONObject object, Class<T> clazz) {
        return object != null ? object.to(clazz) : null;
    }

    public static <T> List<T> toList(JSONArray array, Class<T> clazz) {
        return array != null ? array.toList(clazz) : new ArrayList<>();
    }

    public static <T> T getObj(JSONArray array, int index, Class<T> clazz) {
        return array != null ? array.getObject(index, clazz) : null;
    }

    public static <T> T getObj(JSONObject object, String key, Class<T> clazz) {
        return object != null ? object.getObject(key, clazz) : null;
    }

    public static <T> List<T> getList(JSONArray array, int index, Class<T> clazz) {
        return JSONUtil.toList(array.getJSONArray(index), clazz);
    }

    /**
     * 从 JSON 对象中获取指定键对应的 JSON 数组，并将其转换为指定类型的列表
     *
     * @param object JSON 对象
     * @param key    指定的键
     * @param clazz  列表中元素对应的类类型
     * @return 转换后的列表，如果键不存在或对应的值不是有效的 JSON 数组，则返回空列表
     */
    public static <T> List<T> getList(JSONObject object, String key, Class<T> clazz) {
        return JSONUtil.toList(object.getJSONArray(key), clazz);
    }

    /**
     * 遍历 JSON 数组中的每个元素
     *
     * @param array    JSON 数组
     * @param clazz    元素对应的类类型
     * @param consumer 处理元素的消费者，接收元素值和其索引
     */
    public static <T> void forEach(JSONArray array, Class<T> clazz, BiConsumer<T, Integer> consumer) {
        IntStream.range(0, array.size()).forEach(i -> consumer.accept(getObj(array, i, clazz), i));
    }

    /**
     * 遍历 JSON 对象中的每个键值对
     *
     * @param object   JSON 对象
     * @param clazz    值对应的类类型
     * @param consumer 处理键值对的消费者
     */
    public static <T> void forEach(JSONObject object, Class<T> clazz, BiConsumer<T, String> consumer) {
        StreamUtil.stream(object.keySet()).forEach(k -> consumer.accept(getObj(object, k, clazz), k));
    }

    /**
     * 读取文件为JSON数组
     *
     * @param path    文件路径
     * @param charset 文件编码
     */
    public static JSONArray readArray(String path, Charset charset) throws APIException {
        return readArray(FileUtil.file(path), charset);
    }

    /**
     * 读取文件为JSON数组
     *
     * @param file    文件对象
     * @param charset 文件编码
     */
    public static JSONArray readArray(File file, Charset charset) throws APIException {
        var jsonStr = StrUtil.trim(FileUtil.readString(file, charset));
        if (StrUtil.isWrap(jsonStr, "[", "]")) {
            return JSON.parseArray(jsonStr);
        }

        return null;
    }

    /**
     * 读取指定路径的文件内容为JSON数组，使用UTF-8编码
     *
     * @param path 文件路径
     * @return JSON数组，如果文件内容不是有效的JSON数组格式则返回null
     * @throws APIException 如果读取文件过程中发生错误
     */
    public static JSONArray readUtf8Array(String path) throws APIException {
        return readArray(path, CharsetUtil.UTF_8);
    }

    /**
     * 读取指定文件对象的内容为JSON数组，使用UTF-8编码
     *
     * @param file 文件对象
     * @return JSON数组，如果文件内容不是有效的JSON数组格式则返回null
     * @throws APIException 如果读取文件过程中发生错误
     */
    public static JSONArray readUtf8Array(File file) throws APIException {
        return readArray(file, CharsetUtil.UTF_8);
    }


    /**
     * 读取文件为JSON对象
     *
     * @param path    文件路径
     * @param charset 文件编码
     * @return JSON对象，如果文件内容不是有效的JSON对象格式则返回null
     * @throws APIException 如果读取文件过程中发生错误
     */
    public static JSONObject readObject(String path, Charset charset) throws APIException {
        return readObject(FileUtil.file(path), charset);
    }

    /**
     * 读取文件为JSON对象
     *
     * @param file    文件对象
     * @param charset 文件编码
     * @return JSON对象，如果文件内容不是有效的JSON对象格式则返回null
     * @throws APIException 如果读取文件过程中发生错误
     */
    public static JSONObject readObject(File file, Charset charset) throws APIException {
        var jsonStr = StrUtil.trim(FileUtil.readString(file, charset));
        if (StrUtil.isWrap(jsonStr, "{", "}")) {
            return JSON.parseObject(jsonStr);
        }

        return null;
    }

    /**
     * 读取指定路径的文件内容为JSON对象，使用UTF-8编码
     *
     * @param path 文件路径
     * @return JSON对象，如果文件内容不是有效的JSON对象格式则可能抛出异常
     * @throws APIException 如果读取文件过程中发生错误
     */
    public static JSONObject readUtf8Object(String path) throws APIException {
        return readObject(path, CharsetUtil.UTF_8);
    }

    /**
     * 读取指定文件对象的内容为JSON对象，使用UTF-8编码
     *
     * @param file 文件对象
     * @return JSON对象，如果文件内容不是有效的JSON对象格式则可能抛出异常
     * @throws APIException 如果读取文件过程中发生错误
     */
    public static JSONObject readUtf8Object(File file) throws APIException {
        return readObject(file, CharsetUtil.UTF_8);
    }
}
